﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Collections;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Diagnostics;

namespace Bixas.Tangibilis.Controls
{
    internal class TouchTransformDecoratorAdapter : TouchUIElementAdapter<TouchTransformDecorator>
    {

        private TouchCursorState CursorOne;
        private TouchCursorState CursorTwo;

        private Point OriginPointOne = new Point(0, 0);
        private Point OriginPointTwo = new Point(0, 0);

        public TouchTransformDecoratorAdapter(TouchTransformDecorator elementAdapted)
            : base(elementAdapted)
        { }

        public override void OnTouchCursorDown(RoutedEventArgs e)
        {
            base.OnTouchCursorDown(e);
            this.RebuildPolygon();
        }

        public override void OnTouchCursorUp(RoutedEventArgs e)
        {
            base.OnTouchCursorUp(e);
            this.RebuildPolygon();
        }

        public override void OnTouchCursorLeave(RoutedEventArgs e)
        {
            base.OnTouchCursorLeave(e);
            this.RebuildPolygon();
        }

        public override void OnTouchCursorMove(RoutedEventArgs e)
        {
            RawTouchCursorInputEventArgs args = e as RawTouchCursorInputEventArgs;
            base.OnTouchCursorMove(e);

            this.ApplyTransform();
        }

        Matrix precTransform = new Matrix();

        private void ApplyTransform()
        {
            Matrix transform = new Matrix();

            Point PointTwo = CursorTwo.LastPosition;
            Point PointOne = CursorOne.LastPosition;

            Point OriginPoint3 = OriginPointOne;
            Point Point3 = PointOne;

            if (OriginPointOne != OriginPointTwo)
            {
                OriginPoint3 = deriveThirdPoint(OriginPointOne, OriginPointTwo);
                Point3 = deriveThirdPoint(PointOne, PointTwo);

                //double anglea = Vector.AngleBetween(v1, v2);
                //double centerX = Vector.Add(Vector.Divide(v2 , 2), PointOne).X;
                //double centerY = Vector.Add(Vector.Divide(v2 , 2), PointOne).Y;

                double[] xt = linearSolution(OriginPointOne.X, OriginPointOne.Y, PointOne.X,
                                             OriginPointTwo.X, OriginPointTwo.Y, PointTwo.X,
                                             OriginPoint3.X, OriginPoint3.Y, Point3.X);

                double[] yt = linearSolution(OriginPointOne.X, OriginPointOne.Y, PointOne.Y,
                                             OriginPointTwo.X, OriginPointTwo.Y, PointTwo.Y,
                                             OriginPoint3.X, OriginPoint3.Y, Point3.Y);

                transform.M11 = xt[0];

                transform.M12 = yt[0];
                transform.M21 = xt[1];
                transform.M22 = yt[1];
                transform.OffsetX = xt[2];
                transform.OffsetY = yt[2];

                DebugWriteMatrix(transform);
            }
            else
            {
                transform.OffsetX = PointOne.X - OriginPointOne.X;
                transform.OffsetY = PointOne.Y - OriginPointOne.Y;
            }

            Matrix t2 = new Matrix();

            Vector v1 = Point.Subtract(OriginPointTwo, OriginPointOne);//new Vector(OriginRightTopPoint.X - OriginLeftTopPoint.X, OriginRightTopPoint.Y - OriginLeftTopPoint.Y);
            Vector v2 = Point.Subtract(PointTwo, PointOne);//new Vector(RightTopPoint.X - LeftTopPoint.X, RightTopPoint.Y - LeftTopPoint.Y);

            double anglea = Vector.AngleBetween(v1, v2);

            double scalex = 1 + (v2.Length - v1.Length) / v1.Length;


            
            t2.Scale(scalex, scalex);
                //t2.OffsetX = PointOne.X - (OriginPointOne.X) + v1.Length - v1.Length * scalex;
                //t2.OffsetY = PointOne.Y - (OriginPointOne.Y) + v1.Length - v1.Length * scalex; 


            t2.RotateAt(anglea, PointOne.X * scalex , PointOne.Y * scalex );
            t2.Translate(PointOne.X - PointOne.X * scalex, PointOne.Y - PointOne.Y * scalex);
            DebugWriteMatrix(t2);

            //double TranslateY = Vector.Add(Vector.Divide(v2, 2), PointOne).Y - Vector.Add(Vector.Divide(v1, 2), OriginPointOne).Y;
            //double TranslateX = Vector.Add(Vector.Divide(v2, 2), PointOne).X - Vector.Add(Vector.Divide(v1, 2), OriginPointOne).X;

            /*if (OriginPointOne != PointOne)
            {
                centerX = PointTwo.X;
                centerY = PointTwo.Y;
            }
            */
            //transform.RotateAt(anglea, centerX, centerY);



            //transform.Translate(TranslateX, TranslateY);
            /*double width = (OriginTopLeftPoint.X - OriginTopRightPoint.X);
            double height = (OriginBottomLeftPoint.Y - OriginTopLeftPoint.Y);

            double w2 = (CurrentTopLeftPoint.X - CurrentTopRightPoint.X);
            double w3 = (CurrentBottomLeftPoint.X - OriginBottomLeftPoint.X);
            double w4 = (CurrentTopRightPoint.Y - OriginTopRightPoint.Y);
            */

            //transform.OffsetX = (LeftCursor..X * 640) - (OriginTopLeftPoint.X * 640);
            //transform.OffsetY = (CurrentTopLeftPoint.Y * 480) - (OriginTopLeftPoint.Y * 480);

            /*double width = (OriginRightPoint.X - OriginLeftPoint.X);
            double height = (OriginBottomPoint.Y - OriginTopPoint.Y);

            double w2 = double.NaN;
            //if (TopCursor.CursorId != RightCursor.CursorId | BottomCursor.CursorId != RightCursor.CursorId | TopCursor.CursorId != LeftCursor.CursorId | BottomCursor.CursorId != LeftCursor.CursorId)
                w2 = (RightCursor.LastPosition.X - LeftCursor.LastPosition.X);

            double w3 = double.NaN;
            //if (TopCursor.CursorId != RightCursor.CursorId | BottomCursor.CursorId != RightCursor.CursorId | TopCursor.CursorId != LeftCursor.CursorId | BottomCursor.CursorId != LeftCursor.CursorId)
                w3 = (BottomCursor.LastPosition.Y - TopCursor.LastPosition.Y);

            double ratio = w2 / width;
            if (!double.IsNaN(ratio))
                transform.M11 = ratio;

            ratio = w3 / height;
            if (!double.IsNaN(ratio))
                transform.M22 = ratio;
            */
            /*
          ratio = w3 / width;
          if (!double.IsNaN(ratio))
              transform.M21 = ratio;

          ratio = w4 / height;
          if (!double.IsNaN(ratio))
              transform.M12 = ratio;
          */
            MatrixTransform t = this.TouchElement.RenderTransform as MatrixTransform;
            Matrix u = t.Matrix;
            precTransform.Invert();
            u.Append(precTransform);
            u.Append(t2);
            this.TouchElement.RenderTransform = new MatrixTransform(u);
            precTransform = t2;
        }

        private void DebugWriteMatrix(Matrix transform)
        {
            Debug.WriteLine(transform.ToString());
        }

        public Point deriveThirdPoint(Point f1, Point f2)
        {
            // a vector from finger 1 to finger 2
            Vector vec = (f2 - f1);
            double vecAngle = Math.Atan2(vec.Y, vec.X);
            double vecLength = vec.Length;

            double x1 = Math.Cos(vecAngle + Math.PI / 4);
            double y1 = Math.Sin(vecAngle + Math.PI / 4);

            double x2 = Math.Cos(vecAngle + 3 * Math.PI / 4);
            double y2 = Math.Sin(vecAngle + 3 * Math.PI / 4);

            // two more vectors, one for each leg of the equilateral right triangle
            // (a triangle can be specified with the length of a side and two angles)
            Vector vec1 = new Vector(x1, y1);
            Vector vec2 = new Vector(x2, y2);

            // slope and intercept for each line
            // intercept derived from http://mathworld.wolfram.com/Line.html (2)
            double slope1 = vec1.Y / vec1.X;
            double intercept1 = f1.Y - slope1 * f1.X;

            double slope2 = vec2.Y / vec2.X;
            double intercept2 = f2.Y - slope2 * f2.X;

            // solve for x and y of the mysterious third finger
            Point f3 = new Point(0, 0);
            f3.X = (intercept2 - intercept1) / (slope1 - slope2);
            f3.Y = slope1 * f3.X + intercept1;

            return f3;
        }

        public double[] linearSolution(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3)
        {
            double a = (((z2 - z3) * (y1 - y2)) - ((z1 - z2) * (y2 - y3))) / (((x2 - x3) * (y1 - y2)) - ((x1 - x2) * (y2 - y3)));

            double b = (((z2 - z3) * (x1 - x2)) - ((z1 - z2) * (x2 - x3))) / (((y2 - y3) * (x1 - x2)) - ((y1 - y2) * (x2 - x3)));

            double c = z1 - (x1 * a) - (y1 * b);

            return new double[3] { a, b, c };
        }


        private void RebuildPolygon()
        {
            precTransform = new Matrix();

            CursorTwo = null;
            CursorOne = null;

            OriginPointOne = new Point();
            OriginPointTwo = new Point();

            IEnumerator enumerator = this.cursorStateObjects.Keys.GetEnumerator();
            while (enumerator.MoveNext())
            {
                TouchCursorState cursorState = ((TouchCursorState)this.cursorStateObjects[enumerator.Current]);
                if (cursorState.IsOver)
                {
                    if (CursorOne == null)
                        CursorOne = cursorState;

                    if (CursorTwo == null)
                        CursorTwo = cursorState;

                    Point position = cursorState.LastPosition;
                    if (position.X < CursorOne.LastPosition.X)
                    {
                        CursorOne = cursorState;
                    }

                    if (position.X > CursorTwo.LastPosition.X)
                    {
                        CursorTwo = cursorState;
                    }


                }
            }

            CursorOne = CursorOne ?? CursorTwo;
            CursorTwo = CursorTwo ?? CursorOne;

            if (CursorOne != null)
            {
                OriginPointOne = CursorOne.LastPosition;
                OriginPointTwo = CursorTwo.LastPosition;

            }
        }

    }


}
